﻿using Delphi.Mimir.Config;
using Delphi.Mimir.Wrapper;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace Delphi.Mimir.Data.Entities.Final {
    public class ManagedProduct {
        public ManagedProduct() {
            ManagedProductPositions = new List<ManagedProductPosition>();
            AssetUniverses = new List<AssetUniverse>();
            CashTransactions = new List<CashTransaction>();
            _symbols = new List<Symbol>();
        }

        private List<Symbol> _symbols;

        public int ManagedProductId { set; get; }
        public Symbol Symbol { set; get; }
        public int SymbolId { set; get; }
        public bool? IsActiveManaged { set; get; }
        public DateTime ValidFromDate { set; get; }
        public DateTime ValidUntilDate { set; get; }
        public virtual ICollection<ManagedProductPosition> ManagedProductPositions { set; get; }
        public virtual ICollection<AssetUniverse> AssetUniverses { set; get; }
        public virtual ICollection<Order> Orders { set; get; }
        public virtual ICollection<CashTransaction> CashTransactions { set; get; }
        
        public List<Symbol> Symbols() {
            // add all Symbols which are flagged Include
            foreach(AssetUniverse au in AssetUniverses) {
                if((au.ExchangeId != null) && (au.Include)) {
                    _symbols.AddRange(au.Exchange.Symbols);
                } else if((au.SymbolId != null) && (au.Include)) {
                    _symbols.Add(au.Symbol);
                }
            }

            // TODO fix this.....
            foreach(AssetUniverse au in AssetUniverses) {
                if ((au.SymbolId != null) && (au.Include)) {
                    _symbols.Remove(au.Symbol);
                }
            }
            return _symbols;
        }

        public Dictionary<Symbol, double> AssetRatios(DateTime date) {
            Dictionary<Symbol, double> ratios = new Dictionary<Symbol, double>();



            return ratios;
        }

        public Decimal NetAssetValue(DateTime date) {
            return CashBalance(date) + AssetValue(date);
        }

        public Decimal CashBalance(DateTime date) {
            Decimal cashBalance = 0;
            try {
                List<CashTransaction> cts = CashTransactions.Where(a => a.TransactionDate <= date).ToList();
                foreach (CashTransaction ct in cts) {
                    cashBalance += ct.AmountRefCurrency;
                }
            } catch {
                // no transactions so Balance = 0
            }
            return cashBalance;
        }

        public Decimal AssetValue(DateTime date) {
            Decimal value = 0;
            Symbol s = new Symbol();
            Frequency f = new Frequency();
            try {
                using(var context = new DelphiContext()) {
                    s = context.Symbols.Where(a => a.SymbolId == ManagedProductId).Single();
                    f = context.Frequencies.Where(a => a.Code == "D").Single();
                }
            } catch {
                return value;
            }

            using(var context = new DelphiContext()) {
                foreach(Order o in Orders) {
                    List<OrderExecution> oes = context.OrderExecutions.Where(a => a.OrderId == o.OrderId).ToList();
                    foreach(OrderExecution oe in oes.Where(a => a.ExecutionDate <= date)) {
                        value += oe.Quantity * SymbolWrapper.GetQuoteByLatestDate(o.Symbol, f, date).Close;
                    }
                }
            }
            return value;
        }

        public List<Symbol> SymbolsInProduct(DateTime date) {
            List<Symbol> symbols = new List<Symbol>();
            using(var context = new DelphiContext()) {
                foreach(Order o in Orders) {
                    //var oes = context.OrderExecutions.Where(a => a.OrderId == o.OrderId && a.ExecutionDate <= date).GroupBy(a => a.Ss)
                }
            }
            return symbols;
        }
    }
    
}
